package xyz.itpath.gen.service.impl;

import cn.hutool.core.io.IoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import xyz.itpath.gen.autoconfigure.ProjectConfiguration;
import xyz.itpath.gen.dto.ClassDefine;
import xyz.itpath.gen.service.GeneratorService;
import xyz.itpath.gen.util.ThymeleafUtils;
import xyz.itpath.gen.util.TypeMapUtils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author zhaom
 * @date 2021/9/27 - 14:16
 */
public abstract class AbstractGeneratorServiceImpl implements GeneratorService {

    private final static Logger log = LoggerFactory.getLogger(GeneratorService.class);

    private final static String BASE_PACKAGE = "src/main/java";

    @Autowired
    private TypeMapUtils typeMapUtils;

    @Autowired
    private ProjectConfiguration projectConfiguration;

    @Override
    public void genCode(String dbName, String tbName, String packageName, OutputStream outputStream) {
        List<ClassDefine> classDefines = convertTableToClassDefine(dbName, tbName, packageName);

        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);

        classDefines.forEach(classDefine -> {
            Map<String, Object> param = new HashMap<>(6);
            Set<String> importString = typeMapUtils.getImportString(classDefine.getClassFields());
            param.put("packageName", packageName);
            param.put("classDescription", classDefine.getClassComment());
            param.put("lowerClassName", classDefine.getLowerClassName());
            param.put("className", classDefine.getClassName());
            param.put("classField", classDefine.getClassFields());
            param.put("imports", importString);

            try {
                // 生成实体类
                genEntity(classDefine, param, zipOutputStream);
                // 生成mapper
                genMapper(classDefine, param, zipOutputStream);
                // 生成mapperXml
                genMapperXml(classDefine, param, zipOutputStream);
                // 生成Service
                genService(classDefine, param, zipOutputStream);
                // 生成ServiceImpl
                genServiceImpl(classDefine, param, zipOutputStream);
                // 生成Controller
                genController(classDefine, param, zipOutputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    private void genEntity(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/Entity", param);
        String fileName = classDefine.getClassName() + "Entity.java";
        writeToFile(classDefine.getBasePackage() + File.separator + "entity", fileName, content, zipOutputStream);
    }

    private void genMapper(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/Mapper", param);
        String fileName = classDefine.getClassName() + "Mapper.java";
        writeToFile(classDefine.getBasePackage() + File.separator + "mapper", fileName, content, zipOutputStream);
    }

    private void genMapperXml(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/MapperXml", param);
        String fileName = classDefine.getClassName() + "Mapper.xml";
        writeToFile(classDefine.getBasePackage() + File.separator + "mapper" + File.separator + "xml", fileName, content, zipOutputStream);
    }

    private void genService(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/Service", param);
        String fileName = "I" + classDefine.getClassName() + "Service.java";
        writeToFile(classDefine.getBasePackage() + File.separator + "service", fileName, content, zipOutputStream);
    }

    private void genServiceImpl(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/ServiceImpl", param);
        String fileName = classDefine.getClassName() + "ServiceImpl.java";
        writeToFile(classDefine.getBasePackage() + File.separator + "service" + File.separator + "impl", fileName, content, zipOutputStream);
    }

    private void genController(ClassDefine classDefine, Map<String, Object> param, ZipOutputStream zipOutputStream) throws IOException {
        String content = ThymeleafUtils.genCode(projectConfiguration.getTypeDao() + "/Controller", param);
        String fileName = classDefine.getClassName() + "Controller.java";
        writeToFile(classDefine.getBasePackage() + File.separator + "controller", fileName, content, zipOutputStream);
    }

    /**
     * 将生成的代码字符串写入文件中
     */
    protected void writeToFile(String packageName, String fileName, String content, ZipOutputStream zipOutputStream) throws IOException {
        String entryName = BASE_PACKAGE + File.separator +
                packageName.replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + fileName;
        zipOutputStream.putNextEntry(new ZipEntry(entryName));
        IoUtil.write(zipOutputStream, false, content.getBytes(StandardCharsets.UTF_8));
    }
}
